package com.mashibing.monitor.task;

import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.monitor.client.CacheClient;
import com.mashibing.monitor.utils.MailUtil;
import com.rabbitmq.client.Channel;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Set;

/**
 * @author SNA
 * @date 2025/10/22
 * @Description 监控队列中的消息个数，如果队列消息超过10000条，直接发送短信，通知。
 **/
@Component
@Slf4j
public class MonitorQueueMessageCountTask {

    // 发邮件通知的内容
    String text = "<h1>您的消息队列堆积了，队列名为%s，消息个数为%s</h1>";

    // 队列消息限制
    private final long MESSAGE_COUNT_LIMIT = 10000;

    // 查询所有队列名称的固定pattern
    private final String QUEUE_PATTERN = "channel:*";

    // 得到需要截取channelID的索引地址
    // "channel:*".indexOf("*") 是Java中 String 类的一个方法调用，用于查找字符 '*' 在字符串 "channel:*" 中第一次出现的位置。
    private final int CHANNEL_ID_INDEX = QUEUE_PATTERN.indexOf("*");

    @Autowired
    private CacheClient cacheClient;

    // 注入RabbitMQ的ConnectionFactory
    @Autowired
    private ConnectionFactory connectionFactory;

    @Autowired
    private MailUtil mailUtil;


    /**
     * 监控队列消息数量任务
     * 该方法通过XXL-JOB定时执行，用于监控RabbitMQ队列中的消息数量，
     * 当队列消息积压时发送告警邮件通知相关人员。
     *
     * @throws MessagingException 邮件发送异常
     */
    @XxlJob("monitorQueueMessageCount")
    public void monitor() throws MessagingException {
        //1、拿到所有的队列名称
        Set<String> keys = cacheClient.keys(QUEUE_PATTERN);

        //2、需要基于channel去操作
        Connection connection = connectionFactory.createConnection();
        Channel channel = connection.createChannel(false);

        // 监听短信预发送队列并发送邮件告警
        listenQueueAndSendEmail(channel, RabbitMQConstants.SMS_PRE_SEND);

        // 遍历所有缓存中的队列key，构建对应的网关队列名称并监听
        for (String key : keys) {
            // key.substring(8) 是Java中 String 类的 substring 方法调用，用于从指定索引位置开始截取字符串。
            // 封装队列名称
            String queueName = RabbitMQConstants.SMS_GATEWAY + key.substring(CHANNEL_ID_INDEX);

            listenQueueAndSendEmail(channel, queueName);
        }
    }


    /**
     * 监听指定队列并根据消息数量决定是否发送邮件通知
     *
     * @param channel RabbitMQ通道对象，用于与消息队列进行交互
     * @param queueName 需要监听的队列名称
     * @throws MessagingException 当邮件发送过程中出现异常时抛出
     */
    private void listenQueueAndSendEmail(Channel channel, String queueName) throws MessagingException {
        // 声明队列，如果队列不存在则创建，已存在则忽略
        try {
            channel.queueDeclare(queueName, true, false, false, null);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 拿到对应队列的消息，确认消息数量，超过限制，及时通知
        long count = 0;
        try {
            count = channel.messageCount(queueName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 当队列消息数量超过预设阈值时，发送邮件告警通知
        if (count > MESSAGE_COUNT_LIMIT) {
            // 使用邮件工具类发送告警邮件，内容包含队列名称和当前消息数量
            mailUtil.sendEmail(queueName + "队列消息堆积", String.format(text, queueName, count));
        }
    }

}
